import csv
import re
from datetime import datetime
from decimal import Decimal
from typing import List, Dict

class EmCreditStockPosition:
    def __init__(self):
        # 序号
        self.sequence = 0
        # 证券代码
        self.stock_code = ""
        # 证券名称
        self.stock_name = ""
        # 持仓数量
        self.position_quantity = 0
        # 可用数量
        self.available_quantity = 0
        # 成本价
        self.cost_price = Decimal(0)
        # 最新价
        self.latest_price = Decimal(0)
        # 持仓盈亏比例
        self.position_profit_loss_ratio = ""
        # 持仓盈亏
        self.position_profit_loss = Decimal(0)
        # 当日盈亏比例
        self.daily_profit_loss_ratio = ""
        # 当日盈亏
        self.daily_profit_loss = Decimal(0)
        # 个股仓位
        self.stock_position_ratio = ""
        # 最新市值
        self.market_value = Decimal(0)
        # 交易市场
        self.trading_market = ""
        # 股东账号
        self.shareholder_account = ""
        # 币种
        self.currency = ""

    def __repr__(self):
        return (f"EmCreditStockPosition(代码:{self.stock_code}, 名称:{self.stock_name}, "
                f"数量:{self.position_quantity}, 市价:{self.latest_price})")


class EmCreditPosition:
    def __init__(self):
        # 导出时间
        self.export_time = None
        # 总资产
        self.total_assets = Decimal(0)
        # 净资产
        self.net_assets = Decimal(0)
        # 总仓位
        self.total_position_ratio = ""
        # 总市值
        self.total_market_value = Decimal(0)
        # 持仓盈亏
        self.position_profit_loss = Decimal(0)
        # 当日盈亏
        self.daily_profit_loss = Decimal(0)
        # 可用资金
        self.available_funds = Decimal(0)
        # 可取资金
        self.withdrawable_funds = Decimal(0)
        # 可用保证金
        self.available_margin = Decimal(0)
        # 总负债
        self.total_liabilities = Decimal(0)
        # 维持担保比率
        self.maintenance_margin_ratio = ""
        # 剩余额度
        self.remaining_quota = Decimal(0)
        # 持仓项列表
        self.position_items: List[EmCreditStockPosition] = []
    def __repr__(self):
        return (f"EmCreditPosition(时间:{self.export_time}, 总资产:{self.total_assets}, "
                f"持仓数:{len(self.position_items)})")


class EmCreditPositionParser:
    def __init__(self):
        self.headers = {}  # 存储表头映射
        pass

    def parse(self, file_path: str) -> EmCreditPosition:
        """解析以多个空格为分隔符的CSV文件

        Args:
            file_path: CSV文件路径，列分隔符为2个或更多空格

        Returns:
            EmCreditPosition: 解析后的持仓对象

        Raises:
            ValueError: 当文件格式不符合预期时
        """
        position = EmCreditPosition()

        with open(file_path, 'r', encoding='gbk') as file:
            lines = [line.strip() for line in file if line.strip()]  # 读取非空行

            if len(lines) < 3:
                raise ValueError("CSV文件格式错误：至少需要3行数据（表头+概要+持仓）")

            # 解析账户概要信息（从第二行开始找实际数据）
            summary_found = False
            header_found = False

            for i, line in enumerate(lines):
                if line.startswith('20'):  # 识别日期行
                    row = re.split(r'\s{2,}', line)  # 按2个及以上空格分割
                    self.parse_summary(position, row)
                    summary_found = True
                    stock_lines = lines[i + 1:]  # 后续为持仓数据
                    break

            if not summary_found:
                raise ValueError("未找到有效的账户概要信息行")

            # 查找表头行（第三行）
            for i, line in enumerate(stock_lines):
                if '序' in line and '证券代码' in line and '证券名称' in line:
                    # 找到表头行
                    header_row = re.split(r'\s{2,}', line)
                    self.parse_headers(header_row)
                    header_found = True
                    stock_lines = stock_lines[i + 1:]  # 后续为持仓数据
                    break

            if not header_found:
                raise ValueError("未找到有效的表头行")

            # 解析持仓明细
            for line in stock_lines:
                if line[0].isdigit():  # 验证序号列
                    row = re.split(r'\s{2,}', line)
                    if len(row) >= len(self.headers):
                        stock_position = self.parse_stock_position_by_headers(row)
                        position.position_items.append(stock_position)

        return position

    def parse_summary(self,position: EmCreditPosition, summary_row: List[str]):
        """解析概要信息行"""
        try:
            # 处理时间字段（合并日期和时间部分）
            time_str = ' '.join(summary_row[0].strip().split()[:2])
            position.export_time = datetime.strptime(time_str, "%Y/%m/%d %H:%M")

            # 解析数值字段
            position.total_assets = Decimal(summary_row[1].strip())
            position.net_assets = Decimal(summary_row[2].strip())
            position.total_position_ratio = summary_row[3].strip()
            position.total_market_value = Decimal(summary_row[4].strip())
            position.position_profit_loss = Decimal(summary_row[5].strip())

            # 处理可能为"--"的字段
            position.daily_profit_loss = (
                Decimal(0) if summary_row[6].strip() == "--"
                else Decimal(summary_row[6].strip())
            )

            position.available_funds = Decimal(summary_row[7].strip())
            position.withdrawable_funds = Decimal(summary_row[8].strip())
            position.available_margin = Decimal(summary_row[9].strip())
            position.total_liabilities = Decimal(summary_row[10].strip())
            position.maintenance_margin_ratio = summary_row[11].strip()
            position.remaining_quota = Decimal(summary_row[12].strip())

        except (IndexError, ValueError) as e:
            raise ValueError(f"解析概要信息出错: {str(e)}") from e

    def parse_headers(self, header_row: List[str]):
        """解析表头，建立列名到索引的映射"""
        self.headers = {}
        for i, header in enumerate(header_row):
            header = header.strip()
            if header:  # 忽略空表头
                self.headers[header] = i
        print(f"解析到的表头映射: {self.headers}")

    def get_column_value(self, row: List[str], column_name: str, default=""):
        """根据列名获取值"""
        if column_name in self.headers:
            index = self.headers[column_name]
            if index < len(row):
                return row[index].strip()
        return default

    def parse_stock_position_by_headers(self, row: List[str]) -> EmCreditStockPosition:
        """基于表头解析单只股票持仓信息"""
        position = EmCreditStockPosition()
        try:
            # 使用表头映射获取数据
            position.sequence = int(self.get_column_value(row, "序", "0"))
            position.stock_code = self.get_column_value(row, "证券代码")
            position.stock_name = self.get_column_value(row, "证券名称")
            position.position_quantity = int(self.get_column_value(row, "持仓数量", "0"))
            position.available_quantity = int(self.get_column_value(row, "可用数量", "0"))
            position.cost_price = Decimal(self.get_column_value(row, "成本价", "0"))
            position.latest_price = Decimal(self.get_column_value(row, "最新价", "0"))
            position.position_profit_loss_ratio = self.get_column_value(row, "持仓盈亏比例")
            position.position_profit_loss = Decimal(self.get_column_value(row, "持仓盈亏", "0"))
            position.daily_profit_loss_ratio = self.get_column_value(row, "当日盈亏比例")

            daily_profit_loss = self.get_column_value(row, "当日盈亏", "0")
            position.daily_profit_loss = (
                Decimal(0) if daily_profit_loss == "--"
                else Decimal(daily_profit_loss)
            )

            position.stock_position_ratio = self.get_column_value(row, "个股仓位")
            position.market_value = Decimal(self.get_column_value(row, "最新市值", "0"))
            position.trading_market = self.get_column_value(row, "交易市场")

            # 可选字段，如果不存在则使用默认值
            position.shareholder_account = self.get_column_value(row, "股东账号", "")
            position.currency = self.get_column_value(row, "币种", "人民币")

        except (IndexError, ValueError) as e:
            raise ValueError(f"解析股票持仓出错(行内容: {row}): {str(e)}") from e

        return position

    def parse_stock_position(self, row: List[str]) -> EmCreditStockPosition:
        """解析单只股票持仓信息（保持向后兼容性）"""
        position = EmCreditStockPosition()
        try:
            position.sequence = int(row[0].strip())
            position.stock_code = row[1].strip()
            position.stock_name = row[2].strip()
            position.position_quantity = int(row[3].strip())
            position.available_quantity = int(row[4].strip())
            position.cost_price = Decimal(row[5].strip())
            position.latest_price = Decimal(row[6].strip())
            position.position_profit_loss_ratio = row[7].strip()
            position.position_profit_loss = Decimal(row[8].strip())
            position.daily_profit_loss_ratio = row[9].strip()

            position.daily_profit_loss = (
                Decimal(0) if row[10].strip() == "--"
                else Decimal(row[10].strip())
            )

            position.stock_position_ratio = row[11].strip()
            position.market_value = Decimal(row[12].strip())
            position.trading_market = row[13].strip()
            position.shareholder_account = row[14].strip()
            position.currency = row[15].strip()

        except (IndexError, ValueError) as e:
            raise ValueError(f"解析股票持仓出错(行内容: {row}): {str(e)}") from e

        return position

# 使用示例
if __name__ == "__main__":
    try:
#         # 示例CSV数据（实际使用时替换为文件路径）
#         sample_csv = """导出时间,总资产,净资产,总仓位,总市值,持仓盈亏,当日盈亏,可用资金,可取资金,可用保证金,总负债,维持担保比率,剩余额度
# 2025/06/10 05:55,394453.98,394453.98,99.51%,392536.00,162743.48,--,1917.98,1917.98,276693.18,0.00,10000000000.00%,988700.00
# 序号,证券代码,证券名称,持仓数量,可用数量,成本价,最新价,持仓盈亏比例,持仓盈亏,当日盈亏比例,当日盈亏,个股仓位,最新市值,交易市场,股东账号,币种
# 1,600036,招商银行,7700,7700,23.196,44.600,92.275%,164814.40,--,--,87.06%,343420.000,沪市A股,E073329245,人民币
# 2,300750,宁德时代,200,200,255.935,245.580,-4.046%,-2070.92,--,--,12.45%,49116.000,深市A股,0607258185,人民币"""
#
#         with open('sample_portfolio.csv', 'w', encoding='gbk') as f:
#             f.write(sample_csv)

        sample_csv = "../../test/data/report/20250607_xy.txt"
        # 解析CSV文件
        parser = EmCreditPositionParser()
        portfolio = parser.parse(sample_csv)

        # 打印解析结果
        print("解析成功！")
        print(portfolio)
        print("持仓详情:")
        for stock in portfolio.position_items:
            print(f"  {stock}")

        # 验证数据
        print(f"\n验证数据:")
        print(f"总持仓盈亏(计算): {sum(s.position_profit_loss for s in portfolio.position_items)}")
        print(f"总持仓盈亏(报表): {portfolio.position_profit_loss}")

    except Exception as e:
        print(f"解析出错: {str(e)}")